package com.huihe.framework.service;

import com.huihe.framework.context.AuthenticationContextHolder;
import com.huihe.storage.dto.LoginBody;
import com.huihe.storage.dto.LoginUser;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.stereotype.Service;

/**
 * 登录 Service层
 * 日志格式 :
 *     [LOGI] : login 登录
 *     [UPVE] : username password verify 用户名、密码 验证
 */
@Slf4j
@Service
@AllArgsConstructor
public class LoginService {

    /**
     * 处理身份验证 AuthenticationManager
     * 注入的类为 : config.com.huihe.framework.SecurityConfig 类中的方法 authenticationManager 生成的 ProviderManager Bean
     */
    AuthenticationManager authenticationManager;

    /**
     * Token 的工具类
     */
    TokenService tokenService;

    /**
     * 登录验证方法
     * @param loginBody 需要验证的信息
     * @return 登录之后产生的 Token
     */
    public String login(LoginBody loginBody){
        // 日志打印
        log.info("======================登录请求======================");
        log.info("请求登录的用户名:{}",loginBody.getUsername());
        // 验证成功的用户名和密码 , 如果失败则任然为 NULL
        Authentication authentication;
        try {
            // 将用户输入的用户名和密码保存到中间变量中，为之后调用做准备
            UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(loginBody.getUsername(),loginBody.getPassword());
            // 将用户信息保存到上下文，方便之后验证时调用
            AuthenticationContextHolder.setContext(authenticationToken);
            // 使用 AuthenticationManager 开始验证 UsernamePasswordAuthenticationToken
            authentication = authenticationManager.authenticate(authenticationToken);
        } catch (AuthenticationException e){
            // 异常日志
            log.error("[LOGI] [UPVE] " + e.getMessage(),e);
            // 重新抛出一个新的 RuntimeException 打断后续的执行 , 该异常会在异常捕捉器 GlobalExceptionHandler 处捕捉到
            throw new RuntimeException();
        } finally {
            // 清理登录验证的上下文
            AuthenticationContextHolder.clearContext();
        }
        // 从 Authentication 结果中获得验证成功的登录信息 LoginUser
        LoginUser loginUser = (LoginUser) authentication.getPrincipal();
        String token = tokenService.createToken(loginUser);
        log.info("======================登录成功======================");
        // 返回 Token
        return token;
    }
}
